﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using ActionLogic;
using BehaviorModel.Block;
using BehaviorModel.Block.Finish;
using BehaviorModel.Block.Generator;
using BehaviorModel.Block.ServiceChannel;
using BehaviorModel.Block.Splitter;
using BehaviorModel.Block.Summator;

namespace BehaviorModel.Statistic
{
    public class SystemStatistic : ISystemStatistic
    {
        private Dictionary<Guid, IBlockStatistic> _blockStatistics;

        public long CountOfGenerated { get; private set; }

        public long CountOfPassed
        {
            get { return StatisticController.GetInstance().Collector.CountOfPassed; }
        }

        public long CountInSystem
        {
            get
            {
                if (CountOfGenerated > CountOfPassed)
                    return CountOfGenerated - CountOfPassed;
                return 0;
            }
        }

        public long CountOfWorkingSC { get; private set; }


        public long CountOfRejected
        {
            get { return StatisticController.GetInstance().Collector.CountOfRejected; }
        }

        public long CountOfServiced
        {
            get { return StatisticController.GetInstance().Collector.CountOfServiced; }
        }

        public double RejectProbability
        {
            get
            {
                if ((CountOfRejected + CountOfServiced) != 0)
                {
                    return ((double) CountOfRejected)/(CountOfRejected + CountOfServiced);
                }
                return 0;
            }
        }


        public double AvgCommonServiceTime
        {
            get { return StatisticController.GetInstance().Collector.AvgCommonServicedTime; }
        }

        public double AvgCommonWaitingTime
        {
            get { return StatisticController.GetInstance().Collector.AvgCommonWaitingTime; }
        }

        public double AvgCommonLiveTime
        {
            get { return StatisticController.GetInstance().Collector.AvgCommonLiveTime; }
        }


        public double ServAvgCommonServiceTime
        {
            get { return StatisticController.GetInstance().Collector.ServAvgCommonServicedTime; }
        }

        public double ServAvgCommonWaitingTime
        {
            get { return StatisticController.GetInstance().Collector.ServAvgCommonWaitingTime; }
        }

        public double ServAvgCommonLiveTime
        {
            get { return StatisticController.GetInstance().Collector.ServAvgCommonLiveTime; }
        }

        public double RejAvgCommonServiceTime
        {
            get { return StatisticController.GetInstance().Collector.RejAvgCommonServicedTime; }
        }

        public double RejAvgCommonWaitingTime
        {
            get { return StatisticController.GetInstance().Collector.RejAvgCommonWaitingTime; }
        }

        public double RejAvgCommonLiveTime
        {
            get { return StatisticController.GetInstance().Collector.RejAvgCommonLiveTime; }
        }

        #region IExecutable

        public Action Execute
        {
            get { return Update; }
        }

        public double Priority
        {
            get { return 0; }
        }

        public bool IsBackground
        {
            get { return true; }
        }

        public event Action<IExecutable> OnActionExecuted;

        #endregion

        public SystemStatistic()
        {
            _blockStatistics = new Dictionary<Guid, IBlockStatistic>();
        }

        public void SubscribeOnUpdating(IBlock block)
        {
            switch (block.Type)
            {
                case BlockType.Generator:
                    var generator = (IGenerator) block;
                    _blockStatistics.Add(generator.Id, new GeneratorStatistic(generator));
                    break;
                case BlockType.ServiceChannel:
                    var serviceChannel = (IServiceChannel) block;
                    _blockStatistics.Add(serviceChannel.Id, new ServiceChannelStatistic(serviceChannel));
                    break;
                case BlockType.Summator:
                    var summator = (ISummator) block;
                    _blockStatistics.Add(summator.Id, new SummatorStatistic(summator));
                    break;
                case BlockType.Splitter:
                    var splitter = (ISplitter) block;
                    _blockStatistics.Add(splitter.Id, new SplitterStatistic(splitter));
                    break;
            }
        }

        public void UnsubscribeOnUpdating(IBlock block)
        {
            _blockStatistics.Remove(block.Id);
        }

        public IBlockStatistic this[Guid id]
        {
            get { return _blockStatistics[id]; }
        }

        public void Update()
        {
            foreach (var stat in _blockStatistics)
            {
                stat.Value.Update();
            }

            UpdateCountOfGenerated();
            UpdateCountOfWorkingSC();
        }

        private void UpdateCountOfGenerated()
        {
            CountOfGenerated = _blockStatistics.Where(stat => stat.Value is IGeneratorStatistic).Sum(
                stat => (stat.Value as IGeneratorStatistic).CountOfGenerated);
        }

        private void UpdateCountOfWorkingSC()
        {
            CountOfWorkingSC = _blockStatistics.Where(stat => stat.Value is IServiceChannelStatistic).Count(
                stat => (stat.Value as IServiceChannelStatistic).IsBusy);
        }
    }
}